home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Think Class Libraries / CMIDI 2.2 / CMIDIOutputPort.cp < prev    next >
Encoding:
Text File  |  1994-11-30  |  7.0 KB  |  199 lines  |  [TEXT/KAHL]

  1. /*
  2.  *——— CMIDIOutputPort.cp ———————————————————————————————————————————————————————————————
  3.  * Copyright © Paul Ferguson, 1990-94.  All rights reserved.
  4.  *
  5.  * Superclass:  CDataPort
  6.  * Subclasses:  None
  7.  *
  8.  * Description:
  9.  *    CMIDIOutputPort.c defines a MIDI Manager port object.
  10.  *
  11.  *    For use with Symantec C++ 6.0, the accompanying THINK Class Library (TCL), and MIDI
  12.  *    Manager 2.0. Refer to the accompanying Microsoft Word document for complete
  13.  *    details about MIDI Manager objects.
  14.  *
  15.  *    If you have comments or questions about this code, you can reach me on
  16.  *    CompuServe at 70441,3055.
  17.  *
  18.  *——————————————————————————————————————————————————————————————————————————————————————
  19.  *———— NOTE ——— NOTE ——— NOTE ——— NOTE ——— NOTE ——— NOTE ——— NOTE ——— NOTE ——— NOTE ————
  20.  *——————————————————————————————————————————————————————————————————————————————————————
  21.  *    If you are not familiar with programming the Apple MIDI Manager, refer to the
  22.  *    "MIDI Management Tools" Version 2.0, available from APDA.  You MUST have the
  23.  *    software (MIDI.H and the library) from this package in order to use these objects.
  24.  *    It will not work without this.
  25.  *——————————————————————————————————————————————————————————————————————————————————————
  26.  *    REVISION HISTORY:
  27.  *        August ??, 1990            - Original release (1.0).
  28.  *        November 5, 1990        - Added checks for midiMgrVer to most methods.
  29.  *        August 1991                - updated for THINK C 5.0 as version 2.0
  30.  *        July 1993                - updated for Symantec C++ 6.0.  Inlined simple methods.
  31.  *——————————————————————————————————————————————————————————————————————————————————————
  32.  */
  33.  
  34. #include "CMIDIOutputPort.h"
  35. #include "CMIDITimePort.h"
  36.  
  37. static const int midiWritePacket = 108;        // EQU from MIDI.a
  38.  
  39. static pascal OSErr (*CMIDIOutputPort::midiWriteProc) (short refnum, MIDIPacketPtr packet);
  40.  
  41. /*
  42.  *——— IMIDIOutputPort ————————————————————————————————————————————————————————————
  43.  * Initialize the Output Port object.  This method sets up the MIDIPortParams data
  44.  * structure and calls CMIDIPort::IMIDIPort().  If version is >= 2.0, then save
  45.  * any direct ProcPtrs.
  46.  *————————————————————————————————————————————————————————————————————————————————
  47.  */
  48.  
  49. OSErr CMIDIOutputPort::IMIDIOutputPort(StringPtr        theName,
  50.                                        OSType            thePortID,
  51.                                        Boolean            theVisibleFlag,
  52.                                        CMIDITimePort *    theTimePort,
  53.                                        long                theOffset)
  54. {
  55.     MIDIPortParams        portParams;        // MIDI Mgr Init data structure
  56.     OSErr                theResult;
  57.  
  58.     portParams.portID            = thePortID;
  59.     portParams.portType            = midiPortTypeOutput;
  60.     if ( (theVisibleFlag == FALSE) && (itsVersion >= 0x0200) )    // Invisible output port, in 2.x
  61.         portParams.portType        |= midiPortInvisible;
  62.  
  63.     portParams.timeBase            = theTimePort ? theTimePort->GetRefNum() : 0;
  64.     portParams.offsetTime        = theOffset;
  65.     portParams.readHook            = (Ptr) 0;
  66.     portParams.refCon            = SetCurrentA5();
  67.     BlockMove(theName, portParams.name, theName[0]+1);
  68.  
  69.     theResult = IMIDIPort(&portParams, 0);
  70.  
  71.     if (itsVersion >= 0x200)
  72.     {
  73.         midiWriteProc = (pascal OSErr (*) (short, MIDIPacketPtr)) MIDICallAddress(midiWritePacket);
  74.     }
  75.  
  76.     return theResult;
  77. }
  78.  
  79.  
  80. /*
  81.  *——— CMIDIOutputPort::DoMIDIWrite ————————————————————————————————————————————
  82.  * This local function does all the real work of sending MIDI data.
  83.  *
  84.  * This method is classified as 'private' in CMIDI.h.  If you wish to call
  85.  * this method directly, simply change the header file.
  86.  *
  87.  * If you know your application is going to write a lot of short or fixed
  88.  * length packets, you may wish to override or modify this method to remove the
  89.  * BlockMove trap and multi-length packet logic overhead.
  90.  *
  91.  * It is called by CMIDIOutputPort::Write() and CMIDIOutputPort::WriteTS().
  92.  *—————————————————————————————————————————————————————————————————————————————
  93.  */
  94.  
  95. OSErr CMIDIOutputPort::DoMIDIWrite(    char *            theData,
  96.                                     short            theDataLen,
  97.                                     unsigned char    theFlags,
  98.                                     long            theTimeStamp)
  99. {
  100.     MIDIPacket                midiPacket;        // MIDI Manager packet to be transmitted
  101.     register MIDIPacketPtr    midiPPtr = &midiPacket;
  102.     
  103.     if (itsVersion == 0) return (ErrNoMIDI);
  104.     
  105.     if (theDataLen < 250)            // Handle short packets directly
  106.     {
  107.         midiPPtr->flags = theFlags | midiMsgType | midiNoCont;
  108.         midiPPtr->len   = theDataLen + 6;
  109.         if (theFlags == midiTimeStampValid)
  110.             midiPPtr->tStamp = theTimeStamp;
  111.         BlockMove(theData, &(midiPPtr->data[0]), theDataLen);
  112.         if (midiWriteProc)
  113.             return (*midiWriteProc) (itsRefNum, &midiPacket);        // ••• Call MIDI Manager
  114.         else
  115.             return MIDIWritePacket(itsRefNum, &midiPacket);
  116.     }
  117.     else                    // Multiple packet send    (more than 249 bytes)
  118.     {
  119.         register char *    source = theData;
  120.         register short    thisPacketLen;
  121.         OSErr            err;
  122.  
  123.         do
  124.         {
  125.             midiPPtr->flags  = theFlags | midiMsgType;        // Re-init each time
  126.             if (theFlags == midiTimeStampValid)
  127.                 midiPPtr->tStamp = theTimeStamp;
  128.             thisPacketLen = (theDataLen < 249) ? theDataLen : 249;
  129.             BlockMove(source, &(midiPPtr->data[0]), thisPacketLen);    // Data to write
  130.             
  131.             // Set the continuation bits field in the flags byte.
  132.             
  133.             theDataLen -= thisPacketLen;
  134.             if (source == theData)                            // the first piece of the message
  135.             {
  136.                 if (theDataLen > 0)                            // Multiple writes required?
  137.                     midiPPtr->flags |= midiStartCont;        // Yes
  138.                 else                                        // Everything fits in one packet
  139.                     midiPPtr->flags |= midiNoCont;            // SHOULD NEVER SEE THIS CASE HERE!
  140.             }
  141.             else
  142.             {
  143.                 if (theDataLen > 0)                            // a middle piece
  144.                     midiPPtr->flags |= midiMidCont;
  145.                 else                                        // Last piece of the message
  146.                     midiPPtr->flags |= midiEndCont;
  147.             }
  148.             midiPPtr->len = thisPacketLen + 6;                // Set the packet length
  149.             if (midiWriteProc)
  150.                 err = (*midiWriteProc) (itsRefNum, &midiPacket);    // ••• Call MIDI Manager
  151.             else
  152.                 err = MIDIWritePacket(itsRefNum, &midiPacket);
  153.             if (err) break;
  154.  
  155.             // You may want to add more sophisticated error handling here.  Also, if you are
  156.             // sending large packets like system exclusive messages, you may need to add a
  157.             // timing delay here so you don't overflow the output buffer or the device.
  158.  
  159.             source += thisPacketLen;                        // Bump pointer
  160.  
  161.         } while (theDataLen > 0);        // Loop for next portion of data
  162.         return err;                        // Indicates last result
  163.     }
  164. }
  165.  
  166.  
  167. /*
  168.  *——— WritePacket —————————————————————————————————————————————————————
  169.  * Call the MIDI Manager to send the specified packet.  This is
  170.  * called by the inline methods Write and WriteTS.
  171.  *—————————————————————————————————————————————————————————————————————
  172.  */
  173.  
  174. OSErr    CMIDIOutputPort::WritePacket(MIDIPacketPtr theMIDIPacket)
  175. {
  176.     if (itsVersion >= 0x200)
  177.         return (*midiWriteProc) (itsRefNum, theMIDIPacket);
  178.     else
  179.         return (itsVersion > 0 ? MIDIWritePacket (itsRefNum, theMIDIPacket) : ErrNoMIDI);
  180. }
  181.  
  182. #ifndef __cplusplus
  183.  
  184.     // if using THINK C compiler, not Symantec C++, these are non-inline methods.
  185.     
  186.     OSErr CMIDIOutputPort::Write(char * theData, short theDataLen)
  187.     {
  188.         return DoMIDIWrite(theData, theDataLen, midiTimeStampCurrent, 0);
  189.     }
  190.     
  191.     OSErr CMIDIOutputPort::WriteTS(char * theData, short theDataLen, long theTimeStamp)
  192.     {
  193.         return DoMIDIWrite(theData, theDataLen, midiTimeStampValid, theTimeStamp);
  194.     }
  195.  
  196. #endif
  197.  
  198. // end of CMIDIOutputPort.cp
  199.